using System;
using Xunit;
using Xunit.Abstractions;
using muduoDotNet;
using muduoDotNet.Messages;
using Google.Protobuf;
using System.Collections.Generic;

namespace muduoDotNet.Tests
{
    public class ProtobufCodecTest
    {
        private readonly ITestOutputHelper _output;
        private readonly ProtobufCodec _codec;

        public ProtobufCodecTest(ITestOutputHelper output)
        {
            _output = output;
            _codec = new ProtobufCodec();
        }

        [Fact]
        public void TestEncodeEchoRequest()
        {
            _output.WriteLine("TestEncodeEchoRequest started");
            
            var request = new EchoRequest
            {
                Message = "Hello, World!",
                Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                ClientId = "test-client-123"
            };

            var encoded = _codec.Encode(request);
            
            Assert.NotNull(encoded);
            Assert.True(encoded.Length >= _codec.HeaderLength);
            
            // 验证消息长度头
            int messageLen = (encoded[0] << 24) | (encoded[1] << 16) | (encoded[2] << 8) | encoded[3];
            Assert.Equal(encoded.Length - _codec.HeaderLength, messageLen);
            
            _output.WriteLine($"Encoded EchoRequest: {encoded.Length} bytes total, {messageLen} bytes message");
        }

        [Fact]
        public void TestDecodeEchoRequest()
        {
            _output.WriteLine("TestDecodeEchoRequest started");
            
            var originalRequest = new EchoRequest
            {
                Message = "Test decode message",
                Timestamp = 1234567890,
                ClientId = "decode-test-client"
            };

            // 编码
            var encoded = _codec.Encode(originalRequest);
            
            // 创建Buffer并添加编码数据
            var buffer = new Buffer();
            buffer.Append(encoded);
            
            // 解码
            bool success = _codec.TryDecode<EchoRequest>(buffer, out var decodedRequest);
            
            Assert.True(success);
            Assert.NotNull(decodedRequest);
            Assert.Equal(originalRequest.Message, decodedRequest.Message);
            Assert.Equal(originalRequest.Timestamp, decodedRequest.Timestamp);
            Assert.Equal(originalRequest.ClientId, decodedRequest.ClientId);
            
            _output.WriteLine($"Successfully decoded EchoRequest: '{decodedRequest.Message}'");
        }

        [Fact]
        public void TestDecodeIncompleteMessage()
        {
            _output.WriteLine("TestDecodeIncompleteMessage started");
            
            var request = new EchoRequest
            {
                Message = "Incomplete test",
                Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                ClientId = "incomplete-client"
            };

            var encoded = _codec.Encode(request);
            
            // 只添加部分数据
            var buffer = new Buffer();
            buffer.Append(encoded.AsSpan(0, encoded.Length / 2).ToArray());
            
            // 尝试解码不完整的消息
            bool success = _codec.TryDecode<EchoRequest>(buffer, out var decodedRequest);
            
            Assert.False(success);
            Assert.Null(decodedRequest);
            
            _output.WriteLine("Correctly handled incomplete message");
        }

        [Fact]
        public void TestCheckMessageComplete()
        {
            _output.WriteLine("TestCheckMessageComplete started");
            
            var request = new EchoRequest
            {
                Message = "Complete check test",
                Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                ClientId = "complete-check-client"
            };

            var encoded = _codec.Encode(request);
            var buffer = new Buffer();
            
            // 测试空缓冲区
            int result = _codec.CheckMessageComplete(buffer);
            Assert.Equal(-1, result);
            
            // 测试只有部分头部
            buffer.Append(encoded.AsSpan(0, 2).ToArray());
            result = _codec.CheckMessageComplete(buffer);
            Assert.Equal(-1, result);
            
            // 测试完整头部但消息不完整
            buffer.Clear();
            buffer.Append(encoded.AsSpan(0, _codec.HeaderLength + 5).ToArray());
            result = _codec.CheckMessageComplete(buffer);
            Assert.Equal(-1, result);
            
            // 测试完整消息
            buffer.Clear();
            buffer.Append(encoded);
            result = _codec.CheckMessageComplete(buffer);
            Assert.True(result > 0);
            Assert.Equal(encoded.Length - _codec.HeaderLength, result);
            
            _output.WriteLine($"CheckMessageComplete returned correct length: {result}");
        }

        [Fact]
        public void TestEncodeDecodeStatusMessage()
        {
            _output.WriteLine("TestEncodeDecodeStatusMessage started");
            
            var status = new StatusMessage
            {
                Type = StatusMessage.Types.StatusType.Info,
                Message = "Test status message",
                Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            };
            status.Metadata.Add("key1", "value1");
            status.Metadata.Add("key2", "value2");

            // 编码解码测试
            var encoded = _codec.Encode(status);
            var buffer = new Buffer();
            buffer.Append(encoded);
            
            bool success = _codec.TryDecode<StatusMessage>(buffer, out var decoded);
            
            Assert.True(success);
            Assert.NotNull(decoded);
            Assert.Equal(status.Type, decoded.Type);
            Assert.Equal(status.Message, decoded.Message);
            Assert.Equal(status.Timestamp, decoded.Timestamp);
            Assert.Equal(2, decoded.Metadata.Count);
            Assert.Equal("value1", decoded.Metadata["key1"]);
            Assert.Equal("value2", decoded.Metadata["key2"]);
            
            _output.WriteLine($"Successfully encoded/decoded StatusMessage with {decoded.Metadata.Count} metadata entries");
        }

        [Fact]
        public void TestEncodeDecodeDataPacket()
        {
            _output.WriteLine("TestEncodeDecodeDataPacket started");
            
            var testData = System.Text.Encoding.UTF8.GetBytes("This is test binary data");
            var packet = new DataPacket
            {
                DataType = "text/plain",
                Payload = ByteString.CopyFrom(testData),
                SequenceNumber = 12345,
                Checksum = "ABCD1234"
            };
            packet.Headers.Add("sender", "test-client");
            packet.Headers.Add("timestamp", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString());

            // 编码解码测试
            var encoded = _codec.Encode(packet);
            var buffer = new Buffer();
            buffer.Append(encoded);
            
            bool success = _codec.TryDecode<DataPacket>(buffer, out var decoded);
            
            Assert.True(success);
            Assert.NotNull(decoded);
            Assert.Equal(packet.DataType, decoded.DataType);
            Assert.Equal(packet.Payload.ToByteArray(), decoded.Payload.ToByteArray());
            Assert.Equal(packet.SequenceNumber, decoded.SequenceNumber);
            Assert.Equal(packet.Checksum, decoded.Checksum);
            Assert.Equal(2, decoded.Headers.Count);
            Assert.Equal("test-client", decoded.Headers["sender"]);
            
            _output.WriteLine($"Successfully encoded/decoded DataPacket with {decoded.Payload.Length} bytes payload");
        }

        [Fact]
        public void TestMultipleMessagesInBuffer()
        {
            _output.WriteLine("TestMultipleMessagesInBuffer started");
            
            // 创建多个消息
            var msg1 = new EchoRequest { Message = "First message", ClientId = "client1", Timestamp = 1000 };
            var msg2 = new EchoRequest { Message = "Second message", ClientId = "client2", Timestamp = 2000 };
            var msg3 = new EchoRequest { Message = "Third message", ClientId = "client3", Timestamp = 3000 };

            // 编码所有消息并连接到一个buffer
            var buffer = new Buffer();
            buffer.Append(_codec.Encode(msg1));
            buffer.Append(_codec.Encode(msg2));
            buffer.Append(_codec.Encode(msg3));
            
            // 逐个解码
            var decodedMessages = new List<EchoRequest>();
            
            while (_codec.CheckMessageComplete(buffer) != -1)
            {
                bool success = _codec.TryDecode<EchoRequest>(buffer, out var decoded);
                Assert.True(success);
                Assert.NotNull(decoded);
                decodedMessages.Add(decoded);
            }
            
            // 验证解码结果
            Assert.Equal(3, decodedMessages.Count);
            Assert.Equal("First message", decodedMessages[0].Message);
            Assert.Equal("Second message", decodedMessages[1].Message);
            Assert.Equal("Third message", decodedMessages[2].Message);
            
            _output.WriteLine($"Successfully decoded {decodedMessages.Count} messages from buffer");
        }

        [Fact]
        public void TestInvalidMessageLength()
        {
            _output.WriteLine("TestInvalidMessageLength started");
            
            var buffer = new Buffer();
            
            // 创建一个包含无效长度的消息头
            var invalidHeader = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }; // 非常大的长度
            buffer.Append(invalidHeader);
            
            // 尝试检查消息完整性，应该抛出异常
            Assert.Throws<NetException>(() => _codec.CheckMessageComplete(buffer));
            
            _output.WriteLine("Correctly handled invalid message length");
        }

        [Fact]
        public void TestEmptyMessage()
        {
            _output.WriteLine("TestEmptyMessage started");
            
            // 创建一个空的EchoRequest
            var emptyRequest = new EchoRequest();
            
            // 编码解码测试
            var encoded = _codec.Encode(emptyRequest);
            var buffer = new Buffer();
            buffer.Append(encoded);
            
            bool success = _codec.TryDecode<EchoRequest>(buffer, out var decoded);
            
            Assert.True(success);
            Assert.NotNull(decoded);
            Assert.Equal("", decoded.Message);
            Assert.Equal("", decoded.ClientId);
            Assert.Equal(0, decoded.Timestamp);
            
            _output.WriteLine("Successfully encoded/decoded empty message");
        }
    }
}